class AxiosError {
	constructor(info={}) {
		this.code = info.code;//"ERR_BAD_REQUEST";
		this.config = info.config;
		this.message = info.message;// "Request failed with status code "+status;
		this.name = info.name;
		if(info.response)
			this.response = info.response;
		if(info.request)
			this.request = info.request;
	}
}
class InterceptorManager{
	constructor() {
		this.handlers = [];
	}
	// fulfilled成功回调，rejected失败回调
	use(fulfilled,rejected){
		this.handlers.push({
			fulfilled,
			rejected
		});
		// 返回的是一个数字，该数字是你添加对象所在数组内的下标
		return this.handlers.length - 1;
	}
}
const defaults = {
	timeout:0
}
class Axios {
	constructor(instanceConfig) {
		// this.defaults的值为全局默认项。
		this.defaults = instanceConfig;
		this.interceptors = {
			request:new InterceptorManager(),
			response:new InterceptorManager()
		}
		
	}
	get(url,config){
		return this({
			url,
			...config
		})
	}
	post(url,data,config){
		return this({
			method:"post",
			url,
			data,
			...config
		})
	}
	request(configOrUrl, config = {}) {
		if (typeof configOrUrl === "string") config.url = configOrUrl;
		else config = configOrUrl;
		config = {
			...this.defaults,
			...config
		}
		// console.log(config);
		config.method = (config.method || "get").toLowerCase();
		// 发送ajax请求
		const dispatchRequest = function () {
			return new Promise(function (resolve, reject) {
				if (config.params) {
					config.url += "?" + Object.keys(config.params).map(key => key + "=" + config.params[key]).join("&");
				}
				
				if(config.baseURL && !config.url.startsWith("http://")){
					config.url = config.baseURL+config.url;
				}
				
				
				const request = new XMLHttpRequest();
				
				// 判断配置对象中是否拥有cancelToken
				if(config.cancelToken){
					config.cancelToken.cancel.then(value=>{
						request.abort();// 取消请求
					})
				}
				
				request.onabort = function(){
					// 当请求被取消后执行
					reject("请求被取消了");
				}
				
				
				if(config.timeout) request.timeout = config.timeout;
				request.responseType = "json";
				request.open(config.method, config.url);
				if(config.headers){
					for(let key in config.headers){
						console.log(key,config.headers[key])
						request.setRequestHeader(key,config.headers[key]);
					}
				}
				
				if(config.method === "post" && config.data){
					if(typeof config.data === "object"){
						request.setRequestHeader("Content-Type","application/json");
						config.data = JSON.stringify(config.data);
					}else request.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
				}
				request.send(config.data);
				
				
				
				
				// 当得到响应信息后执行（请求的资源如果有响应即执行）
				request.onload = function () {
					if(request.status === 200){
						
						resolve({
							// 配置对象信息
							config,
							// 响应头
							headers: request.getAllResponseHeaders(),
							// 响应体
							data: request.response,
							// XMLHttpRequest实例
							request,
							// 状态码
							status: request.status,
							// 状态码说明
							statusText: request.statusText
						})
					}else{
						//404
						reject(new AxiosError({
							code:"ERR_BAD_REQUEST",
							config,
							message:"Request failed with status code "+request.status,
							name:"AxiosError",
							response:request.response
						}))
					}
				}
				request.onerror = function(){
					reject(new AxiosError({
						code:"ERR_NETWORK",
						config,
						message:"Network Error",
						name:"AxiosError",
						request
					}))
				}
				request.ontimeout = function(){
					reject(new AxiosError({
						code:"ECONNABORTED",
						name:"AxiosError",
						config,
						request,
						message:`timeout of ${request.timeout}ms exceeded`					}))
				}
			})
		}
		
		
		// 先有一个数组[dispatchRequest,undefined]
		// 为什么要有一个undefined?答：占位
		const chain = [dispatchRequest.bind(this),undefined];
		// 将axios.interceptors.request.handlers=[
		// {fulfilled:请求拦截成功1，rejected:请求拦截失败1},
		// {fulfilled:请求拦截成功2，rejected:请求拦截失败2},
		// ],放到在chain数组的头部
		this.interceptors.request.handlers.forEach(item=>{
			chain.unshift(item.fulfilled,item.rejected)
		})
		// 分析上方的forEach:
		// const chain = [
		// 请求拦截成功2,请求拦截失败2,
		// 请求拦截成功1,请求拦截失败1,
		// dispatchRequest.bind(this),undefined
		// ];
		
		// 将axios.interceptors.response.handlers = [
		//  {fulfilled:响应拦截成功1，rejected:响应拦截失败1}
		//  {fulfilled:响应拦截成功2，rejected:响应拦截失败2}
		// ],放到在chain数组的尾部
		this.interceptors.response.handlers.forEach(item=>{
			chain.push(item.fulfilled,item.rejected);
		})
		// const chain = [
		// 请求拦截成功2,请求拦截失败2,
		// 请求拦截成功1,请求拦截失败1,
		// dispatchRequest.bind(this),undefined,
		// 响应拦截成功1,响应拦截失败1,
		// 响应拦截成功2,响应拦截失败2
		// ];
		
		let promise = Promise.resolve(config);// config 配置对象
		while(chain.length){// 0
			promise = promise.then(chain.shift(),chain.shift())
		}
		// promise =
		// Promise.resolve(config)
		// .then(请求拦截成功2,请求拦截失败2)
		// .then(请求拦截成功1,请求拦截失败1)
		// .then(dispatchRequest.bind(this),undefined)
		// .then(响应拦截成功1,响应拦截失败1).then(响应拦截成功2,响应拦截失败2)
		
		
		// promise = promise.then(chain[0],chain[1]);
		// promise = promise.then(chain[2],chain[3]);
		// promise = promise.then(chain[4],chain[5]);
		// promise = promise.then(chain[6],chain[7]);
		// promise = promise.then(chain[8],chain[9]);
		
		// promise = promise.then(chain[0],chain[1])
		// 	.then(chain[2],chain[3])
		// 	.then(chain[4],chain[5])
		// 	.then(chain[6],chain[7])
		// 	.then(chain[8],chain[9]);
		return promise;
		
		
		
		
		
	}
}

function createInstance(defaultConfig) {
	const context = new Axios(defaultConfig);
	const instance = Axios.prototype.request.bind(context);
	// 将Axios实例下的属性复制到instance对象中
	for(let key in context){
		instance[key] = context[key];
	}
	// 将Axios.prototype的属性复制到instance对象中
	Object.getOwnPropertyNames(Axios.prototype).forEach(key=>{
		instance[key] = Axios.prototype[key];
	})
	
	
	
	return instance;
}

const axios = createInstance(defaults);

axios.CancelToken = function(cb){
	this.cancel = new Promise(resolve=>{
		cb(resolve);
	})
}

export default axios;